/*
 * @Author: huangwei
 * @Date: 2021-06-09 16:48:36
 * @LastEditors: 黄威
 * @LastEditTime: 2022-03-03 15:49:35
 * @Description: 绘画用的基类（同步二三维接口和操作）
 */

import { Error } from '@/log'
import { equeals, wrap } from '../coordinate'

// 常规绘制使用的事件
const HOOKS = {
    /**
     * 左键点击
     * @param {AbsDraw} drawIns 绘图对象
     * @param {number[]} coord 左键点击
     */
    lclick: function (drawIns, coord) {
        drawIns._handler.addCoord(coord)
    },
    /**
     * 右键点击
     * @param {AbsDraw} drawIns 绘图对象
     */
    rclick: function (drawIns) {
        drawIns._handler.finishShape()
    },
    /**
     * 鼠标移动
     * @param {AbsDraw} drawIns 绘图对象
     * @param {number[]} coord 左键点击
     */
    move: function (drawIns, coord) {
        drawIns._handler._updateGuide(coord)
        drawIns._fireDrawEvt('drawupdate', wrap(coord))
    },
}

export const DRAGHOOKS = {
    /**
     * 左键按下
     * @param {AbsDraw} drawIns 绘图对象
     * @param {number[]} coord 左键点击
     */
    ldown: function (drawIns, coord) {
        if (drawIns._handler.coords.length === 0) {
            drawIns._handler.addCoord(coord)
            drawIns._setDragAble(false)
        }
    },
    /**
     * 左键按下
     * @param {AbsDraw} drawIns 绘图对象
     * @param {number[]} coord 左键点击
     */
    lup: function (drawIns, coord) {
        if (
            drawIns._handler.coords.length === 1 &&
            !equeals(drawIns._handler.coords[0], coord)
        ) {
            drawIns._handler.addCoord(coord)
            drawIns._setDragAble(true)
        }
    },
    /**
     * 左键点击
     * @param {AbsDraw} drawIns 绘图对象
     * @param {number[]} coord 左键点击
     */
    lclick: function (drawIns, coord) {
        if (
            drawIns._handler.coords.length === 1 &&
            !equeals(drawIns._handler.coords[0], coord)
        ) {
            drawIns._handler.addCoord(coord)
            drawIns._setDragAble(true)
        } else {
            drawIns._setDragAble(true)
        }
    },
    /**
     * 右键点击
     * @param {AbsDraw} drawIns 绘图对象
     */
    rclick: function (drawIns) {
        drawIns._handler.finishShape()
        drawIns._setDragAble(true)
    },
    move: HOOKS.move,
}

/**
 * 绑定或者解绑事件
 * @param {AbsDraw} drawIns 绘制对象
 * @param {*} events 绑定是事件
 * @param {boolean} isBind 绑定事件或者解绑事件
 * @returns
 */
function toggleEvents(drawIns, events, isBind) {
    const retEvents = {}

    for (const key in events) {
        const event = events[key]

        if (isBind) {
            // 事件预处理
            const handler = function (evt) {
                // 不存在绘制
                if (!drawIns._handler) return

                // 坐标转换
                const coord = drawIns._evtToCoord(evt)
                if (!coord) return

                // 联动绘制
                const linkDraws = (drawIns.options.linkDraws ?? []) || []
                for (let i = 0; i < linkDraws.length; i++) {
                    const drawIns2 = linkDraws[i]
                    if (!drawIns2 || !drawIns2._handler) return

                    if (drawIns !== drawIns2) {
                        event(drawIns2, coord, evt)
                    }
                }

                // 响应事件
                event(drawIns, coord, evt)
            }
            retEvents[key] = handler

            drawIns._on(key, handler)
        } else {
            drawIns._off(key, event)
        }
    }
    return retEvents
}

// 抽象绘制接口
export class AbsDraw {
    constructor(map, modes) {
        this.map = map
        /**
         * @type {IHandler[]}
         */
        this.modes = modes || this.constructor.modes || {}

        /**
         * @type {IHandler}
         */
        this._handler = null

        // 当前绘制的参数
        this.drawType = null
        this.options = {}
    }

    // 一些抽象接口（事件绑定和坐标转换，地图能否拖动等）
    _on(type, event) {}
    _off(type, event) {}
    _evtToCoord(evt) {}
    _setDragAble(flag) {}

    /**
     * 获取地图元素
     * @returns {HTMLElement}
     */
    _getContainer() {
        return this.map.container
            ? this.map.container.children[0]
            : this.map.getContainer()
    }

    // 触发事件
    _fireDrawEvt(type, val) {
        const events = this.options.events

        if (events && events[type]) {
            try {
                const evt = {
                    target: this,
                    handler: this._handler,
                    coords: this._handler.coords.map(wrap),
                    value: val,
                }
                setTimeout(() => events[type](evt), 32)
            } catch (error) {
                Error('绘制回调执行失败', error)
            }
        }
    }

    startDraw(drawType, options) {
        // 结束上次绘制
        if (this._handler) this.endDraw(false)

        // 绑定配置
        this.drawType = drawType
        this.options = options || {}

        // 判断是否支持绘制
        const Mode = this.modes[drawType]
        if (!Mode) throw '不支持的绘制类型！'

        // 新建新的绘制对象
        this._handler = new Mode(this)
        this._handler.enable()
    }

    endDraw(endSelf = true) {
        if (this._handler) {
            if (!endSelf) this._handler.finishShape(true)
            this._fireDrawEvt('drawend', this._handler.graphic)
            this._handler.disable()
            this._handler = null
            this.options = {}
        }
    }
}

class IHandler {
    hooks = HOOKS

    /**
     * 绘图对象基类
     * @param {AbsDraw} draw 绘图对象
     */
    constructor(draw) {
        this._draw = draw

        // 是否激活
        this._isActive = false

        // 绘画结果相关
        this.coords = []
        this.graphic = null

        // 绘画辅助线
        this._guideG = null

        // 需要支持的事件
        this._hooks = {}
    }

    // 获取绘画样式
    get style() {
        const style = this._draw.options.style || {}

        if (typeof style === 'function') {
            return style(this)
        } else {
            return Object.assign({}, style)
        }
    }

    // 绘画对象存放的地方
    get target() {
        return this._draw.options.layer || this._draw.map
    }

    // 启用和停用接口
    enable() {
        if (this._isActive) return
        this._isActive = true

        // 清空现有的对象
        this.graphic && this.setCoords([])

        // 新建guide，绑定事件
        this._guideG = this._newGuide()
        this._hooks = toggleEvents(this._draw, this.hooks, true)

        this._draw._getContainer().classList.add('mgs-crosshair')
    }
    disable() {
        if (!this._isActive) return
        this._isActive = false

        // 清空事件，清空guide
        this._hooks = toggleEvents(this._draw, this._hooks, false)
        this._guideG = this._clearGuide()

        this._draw._getContainer().classList.remove('mgs-crosshair')
    }

    // 添加和设置坐标接口
    addCoord(coord) {
        this._draw._fireDrawEvt('drawchange', wrap(coord))

        this.coords.push(coord)
        this.setCoords(this.coords)
    }
    setCoords(coords) {
        this.coords = coords

        if (this.isValid()) {
            let needUpdate = true
            // 通过验证，添加绘制对象
            if (!this.graphic) {
                this.graphic = this._newGraphic()
                // 设置坐标类型并添加到target中
                this.graphic
                    .setCoords(this.coords)
                    .setStyle(this.style)
                    .addTo(this.target)
                needUpdate = false
            }
            // 更新绘制对象
            this._updateGraphic(needUpdate)
        }
        // 清空现有的图形
        else if (this.graphic) {
            this._clearGraphic()
        }
    }

    // 完成多边形（用于右键判断，单独提出用于实现repeatMode）
    finishShape(force = false) {
        // finish
        if (this.isValid()) {
            this._draw._fireDrawEvt('drawcreate', this.graphic)
        } else {
            this._draw._fireDrawEvt('drawcancel')
        }

        if (force) return

        let flag = this.isValid()
        if (this._draw.options.alwaysRepeat) flag = true

        // 重复绘制模式
        if (flag && this._draw.options.repeatMode) {
            this.disable()
            // 清空绘制
            this.graphic = null
            this.coords = []
            // 重新开启绘制
            this.enable()
        }
        // 结束绘制
        else {
            this._draw.endDraw(true)
        }
    }

    // 验证多边形是否可用
    isValid() {
        return true
    }

    // feature创建更新销毁
    _newGraphic() {}
    _updateGraphic() {}
    _clearGraphic() {
        if (!this.graphic) return

        this.graphic.remove()
        this.graphic = null
    }

    // 引导线创建更新销毁
    _newGuide() {}
    _updateGuide() {}
    _clearGuide() {
        this._guideG && this._guideG.remove()
        this._guideG = null
    }
}

export class ISimpleHandler extends IHandler {
    // 最小坐标树
    MinLen = 1
    MaxLen = undefined

    isValid() {
        return this.coords.length >= this.MinLen
    }

    setCoords(coords = []) {
        // 边界判断
        if (coords.length > this.MaxLen) {
            coords = coords.slice(-this.MaxLen)
        }

        super.setCoords(coords)
    }

    _updateGraphic(needUpdate = true) {
        needUpdate && this.graphic.setCoords(this.coords)

        // 结束判断
        if (this.coords.length == this.MaxLen) {
            this.finishShape()
        }
    }
}
